package base.juc;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 使用 基于CAS的 AtomicInteger类 实现多线程 安全操作 加减
 *
 * Author: shen qi han
 * Date: 2022/3/21 下午10:13
 */
public class CasMain {

    static int loopCnt = 1000;

    CountDownLatch cdl = new CountDownLatch(4);

    /**
     * 计算类的抽象父类
     */
    abstract class Counter {

        public abstract int getCount();

        public abstract void add();

        public abstract void desc();

    }

    /**
     * 线程安全的计算类
     */
    class CounterSafe extends Counter{

        AtomicInteger count = new AtomicInteger();

        @Override
        public int getCount() {
            return count.get();
        }

        @Override
        public void add() {
            count.addAndGet(1);
        }

        @Override
        public void desc() {
            count.decrementAndGet();
        }
    }

    /**
     * 线程不安全的计算类
     */
    class CounterUnSafe extends Counter{

        /**
         * 这里需要注意 ！！！
         * volatile 只是提供了 可见性（变量每次被线程访问时，都强迫从内存中重新读取该值; 当变量发生改变时，强迫该线程写回到共享内存）
         * 和 有序性（防止多线程环境下，本线程执行语句的指令重排）
         * 但是 不能保证 原子性（cpu不可以暂停再调度，不能被中断。要么执行完成，要么不执行）
         * 具体体现在 无法影响其他线程 cpu已经执行的i++步骤
         */
        volatile int count = 0;

        @Override
        public int getCount() {
            return this.count;
        }

        @Override
        public void add() {
            this.count++;
        }

        @Override
        public void desc() {
            this.count--;
        }
    }

    /**
     * 增加操作 线程
     */
    class AddOptThread implements Runnable{

        Counter counter;

        public AddOptThread(Counter counter){
            this.counter = counter;
        }

        @Override
        public void run() {
            for(int i = 0; i < loopCnt; i++){
                this.counter.add();
            }
            cdl.countDown();
        }
    }

    class DescOptThread implements Runnable{

        Counter counter;

        public DescOptThread(Counter counter){
            this.counter = counter;
        }

        @Override
        public void run() {
            for(int i = 0; i < loopCnt; i++){
                this.counter.desc();
            }
            cdl.countDown();
        }
    }

    /**
     * 结果：
     * UnSafe result is -470
     * Safe result is 0
     *
     * 原因：
     * 线程安全的采用的是 AtomicInteger 作为原子操作，线程安全
     * count++ 操作是线程不安全的，可以参考 JMM模型
     * JMM原理
     *  线程对变量的操作，都必须在工作内存中完成
     *  不能直接读写主内存
     *  不同线程间，只能通过主内存来传递值
     *  所以当线程不安全的情况下，线程对count做了操作，工作内存更新了值，但是由于时间片耗尽的原因，还没有刷新到主内存
     *  另一个线程从 主内存中读取值，读到就是没有被 +1或者-1 操作的值
     */
    public void runSafeOpt(){
        int num = 4;
        CounterSafe safeCounter = new CounterSafe();
        CounterUnSafe unSafeCounter = new CounterUnSafe();
        // full thread
        // safe
        AddOptThread addSafeTask = new AddOptThread(safeCounter);
        DescOptThread descSafeTask = new DescOptThread(safeCounter);
        // unsafe
        AddOptThread addUnSafeTask = new AddOptThread(unSafeCounter);
        DescOptThread descUnSafeTask = new DescOptThread(unSafeCounter);

        ExecutorService pool = Executors.newFixedThreadPool(num);
        pool.submit(addSafeTask);
        pool.submit(descSafeTask);
        pool.submit(addUnSafeTask);
        pool.submit(descUnSafeTask);
        pool.shutdown();

        // wait result
        try {
            // 等待四个线程 操作完成
            cdl.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("UnSafe result is " + unSafeCounter.getCount());
        System.out.println("Safe result is " + safeCounter.getCount());

    }


    public static void main(String[] args) {
        CasMain main = new CasMain();
        main.runSafeOpt();
    }


}
